Web Cryptoで楕円曲線ディフィー・ヘルマン鍵共有して、暗号化 & 復号
#楕円曲線ディフィー・ヘルマン鍵共有 #Web_Crypto #JavaScript #セキュリティ #TypeScript #WebブラウザのJavaScript
window.cryptoを使ってブラウザで鍵の生成、共有・暗号化をするときに使える例。
TypeScriptで書いてるので、型を消去すればJavaScriptでも使える。
以下のrawとdecryptedが同じ[1, 2, 3]になることが確認できればOK。厳密には型がUint8ArrayとArrayBufferで違うが、合わせたくなったときに簡単に合わせられるのでここでは簡単のために触れない。
途中に出てくるaPublicKeyJWKやbPublicKeyJWKはJSONで、JSON.stringify()すればネットワーク経由で渡せる。bRemotePublicKeyはネットワーク経由で渡ってきたものを使ってると解釈すればOK。
code:ts
// (from: https://qiita.com/tomoyukilabs/items/eac94fdb2d0ca92f443a)
(async ()=>{
const aKeyPair: CryptoKeyPair = await window.crypto.subtle.generateKey(
{ name: 'ECDH', namedCurve: 'P-256'},
false,
'deriveKey', 'deriveBits'
);
const aPublicKeyJWK = await crypto.subtle.exportKey('jwk', aKeyPair.publicKey);
console.log(aPublicKeyJWK);
console.log(JSON.stringify(aPublicKeyJWK, null, " "));
const bKeyPair: CryptoKeyPair = await window.crypto.subtle.generateKey(
{ name: 'ECDH', namedCurve: 'P-256'},
false,
'deriveKey', 'deriveBits'
);
const bPublicKeyJWK = await crypto.subtle.exportKey('jwk', bKeyPair.publicKey);
const bRemotePublicKey = await crypto.subtle.importKey(
'jwk',
bPublicKeyJWK,
{name: 'ECDH', namedCurve: 'P-256'},
false,
[]
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const aKey = await crypto.subtle.deriveKey(
{ name: 'ECDH', public: bRemotePublicKey },
aKeyPair.privateKey,
{'name': 'AES-GCM', length: 128},
false,
'encrypt', 'decrypt'
);
const raw = new Uint8Array(1, 2, 3);
const encrypted = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv, tagLength: 128 },
aKey,
raw
);
console.log("encrypted:", encrypted);
const aRemotePublicKey = await crypto.subtle.importKey(
'jwk',
aPublicKeyJWK,
{ name: 'ECDH', namedCurve: 'P-256'},
false,
[]
);
const bKey = await crypto.subtle.deriveKey(
{ name: 'ECDH', public: aRemotePublicKey },
bKeyPair.privateKey,
{ name: 'AES-GCM', length: 128 },
false,
'encrypt', 'decrypt'
);
console.log('aKey:', aKey);
console.log('bKey:', bKey);
const decrypted = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv, tagLength: 128 },
bKey,
encrypted
);
console.log('raw:', raw);
console.log('decrypted:', decrypted);
})();
コードの参考:
関連: Web CryptoでJavaScriptだけでパスワードによる暗号化/復号